package middleware

import (
	"context"
	grpcMiddleware "github.com/grpc-ecosystem/go-grpc-middleware"
	"github.com/opentracing/opentracing-go"
	"github.com/opentracing/opentracing-go/ext"
	"go.zhoushuai.cn/go-programming-tour-book/grpc-pratice/pkg/metatext"
	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"
	"log"
	"time"
)

func RunGrpcServer() *grpc.Server {
	// 实现多个拦截器
	opts := []grpc.ServerOption{
		//grpc.ChainUnaryInterceptor(HelloInterceptor, WordInterceptor),
		grpc.UnaryInterceptor(grpcMiddleware.ChainUnaryServer(
			//HelloInterceptor,
			//WordInterceptor,
			AccessLog,
			ServerTracing,
		)),
	}
	grpcServer := grpc.NewServer(opts...)
	return grpcServer
}

// HelloInterceptor 拦截器
func HelloInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo,
	handler grpc.UnaryHandler) (interface{}, error) {
	log.Println("你好")
	resp, err := handler(ctx, req)
	log.Println("再见")
	return resp, err
}

// WordInterceptor 拦截器
func WordInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo,
	handler grpc.UnaryHandler) (interface{}, error) {
	log.Println("咕咕")
	resp, err := handler(ctx, req)
	log.Println("咩咩")
	return resp, err
}

// AccessLog 访问日志
func AccessLog(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo,
	handler grpc.UnaryHandler) (interface{},
	error) {
	requestLog := "access request log :method :%s,begin-time:%d ,request:%v"
	beginTime := time.Now().Local().Unix()
	log.Printf(requestLog, info.FullMethod, beginTime, req)

	resp, err := handler(ctx, req)

	responseLog := "access response log :method :%s,begin-time:%d,end-time:%d,response:%v"
	endTime := time.Now().Local().Unix()
	log.Printf(responseLog, info.FullMethod, beginTime, endTime, resp)
	return resp, err
}

// ServerTracing 服务端链路追踪
func ServerTracing(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo,
	handler grpc.UnaryHandler) (interface{}, error) {
	var serverSpan opentracing.Span
	operationName := info.FullMethod
	md, ok := metadata.FromIncomingContext(ctx)
	if !ok {
		md = metadata.New(nil)
	}
	parentSpanContext, err := opentracing.GlobalTracer().Extract(opentracing.TextMap, metatext.MetaDataTextMap{MD: md})
	if err != nil {
		// Optionally record something about err here
		log.Printf("ServerTracing[Jhou Shuai] error %v \n", err)
	}
	spanOptions := []opentracing.StartSpanOption{
		opentracing.Tag{Key: string(ext.Component), Value: "gRPC"},
		ext.SpanKindRPCServer,
		ext.RPCServerOption(parentSpanContext),
	}
	serverSpan = opentracing.StartSpan(operationName, spanOptions...)
	defer serverSpan.Finish()
	ctx = opentracing.ContextWithSpan(ctx, serverSpan)
	return handler(ctx, req)

}
